// 基础类型
(() => {
    // 布尔类型   -----> boolean
    // 基本语法
    // let 变量名：数据类型 = 值
    let flag: boolean = true
    flag = false
    // flag = 10    // 报错
    console.log(flag)

    // 数字类型   -----> number
    let a1: number = 10  // 十进制
    let a2: number = 0b1010  // 二进制
    let a3: number = 0o12  // 八进制
    let a4: number = 0xa  // 十六进制
    console.log(a1)
    console.log(a2)
    console.log(a3)
    console.log(a4)
    // a1 = '哈哈'  // 报错

    // 字符串类型   -----> string
    let str1: string = '床前明月光'
    let str2: string = '小明去开窗'
    let str3: string = '遇到一耳光'
    let str4: string = '牙齿掉光光'
    console.log(`${str1},${str2},${str3},${str4}。`)
    // str4 = 10    // 报错

    // 字符串和数字之间能够一起拼接
    let str5: string = '我有这么多的钱:'
    let num: number = 1000000000000
    console.log(str5 + num)

    // 总结：ts中变量一开始是什么类型，那么后期赋值的时候，只能是这个类型的数据，是不允许用其他类型的数据赋值给当前的变量中


    let und: undefined = undefined
    let nll: null = null
    console.log(und)
    console.log(nll)
    // undefined 和 null 都可以作为其他类型的子类型，把undefined 和 null 赋值给其他类型的变量，如number类型的变量
    // let num2: number = undefined
    let num2: number = null
    console.log(num2)


    // 数组类型
    // 数组定义方式1
    // 语法: let 变量名: 数据类型[] = [值1,值2,值3]
    let arr1: number[] = [10, 20, 30, 40]
    // let arr1: number[] = [10,20,30,40,'11']     // 不能将类型“string”分配给类型“number”。
    console.log(arr1)
    // 数组定义方式2
    // 语法: let 变量名: Array<数据类型> = [值1,值2,值3]
    let arr2: Array<number> = [10, 20, 30, 40]
    console.log(arr2)

    // 元组类型
    let arr3: [string, number, boolean] = ['小甜甜', 100, false]
    console.log(arr3[0].split(''))
    console.log(arr3[1].toFixed(2))

    // 枚举类型,枚举里面的每个数据值都可以叫元素，每个元素都有自己的编号，编号时从0开始的，依次的递增加1
    enum Color {
        red,
        green,
        blue
    }
    // 定义一个Color的枚举类型的变量来接手枚举的值
    let color: Color = Color.red
    console.log(color)
    console.log(Color.red, Color.green, Color.blue)
    // 小例子
    enum Gender {
        // 枚举值的元素可以是中文的数据值，但是不推荐
        女,
        男
    }
    console.log(Gender.男)

    // any类型
    // let str: any = 100
    // str = '哈哈哈'
    // console.log(str)

    // 当一个数组中要存储多个数据，个数不确定，类型不确定，此时也可以使用any类型来定义数组
    let arr: any[] = [100, '哈哈哈', true]
    console.log(arr)
    // 这种情况下也没有报错的提示信息，any类型有有点，也有缺点
    // console.log(arr[0].split(''))

    // void类型 在函数申明的时候，小括号后面使用 :void，代表的是该函数没有任何的返回值
    function showMsg(): void {
        console.log('哈哈哈')
        return null
    }
    console.log(showMsg());
    // 定义一个void类型的变量，可以接收一个undefined的值，但是意义不是很大
    let vd: void = undefined
    console.log(vd);

    // object 类型
    // 定义一个函数，参数是object，返回值也是object类型
    function getObj(obj: object): object {
        console.log(obj)
        return {
            name: '卡卡西',
            age: 27
        }
    }
    console.log(getObj({ name: '鸣人', age: 27 }));


    // 联合类型（Union Types）表示取值可以为多种类型中的一种
    // 需求1：定义一个函数得到一个数字或字符串值的字符串形式值
    /* function getString(str:number|string){
        return str.toString()
    }
    console.log(getString('123')) */

    // 需求2：定义一个函数得到一个数字或字符串值的长度
    function getString(str: number | string): number {
        return str.toString().length
    }
    console.log(getString('012345'))
    console.log(getString(12345))


    // 类型断言 // 告诉编译器，我知道我自己是什么类型，也知道自己在干什么
    // 类型断言的语法方式1：<类型>变量名
    // 类型断言的语法方式2：值 as 类型
    function getString2(str: number | string): number {
        // 如果str本身就是string类型，那么是没有必要调用toString()方法的
        if ((<string>str).length) {
            // return (<string>str).length
            return (str as string).length
        } else {
            return str.toString().length
        }
    }
    console.log(getString2('012345'))
    console.log(getString2(12345))

    // 类型推断：没有明确的指定类型的时候推测出一种类型
    // let txt = 100
    // txt = '哈哈哈'
    // console.log(txt)

    let txt2
    txt2 = 100
    txt2 = '哈哈哈'
    console.log(txt2)

})()